package com.game.utils;

import org.jbox2d.collision.shapes.CircleShape;
import org.jbox2d.collision.shapes.PolygonShape;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.collision.shapes.ShapeType;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.BodyDef;
import org.jbox2d.dynamics.BodyType;
import org.jbox2d.dynamics.FixtureDef;
import org.jbox2d.dynamics.World;
import org.jbox2d.dynamics.joints.DistanceJoint;
import org.jbox2d.dynamics.joints.DistanceJointDef;
import org.jbox2d.dynamics.joints.GearJoint;
import org.jbox2d.dynamics.joints.GearJointDef;
import org.jbox2d.dynamics.joints.Joint;
import org.jbox2d.dynamics.joints.MouseJoint;
import org.jbox2d.dynamics.joints.MouseJointDef;
import org.jbox2d.dynamics.joints.PulleyJoint;
import org.jbox2d.dynamics.joints.PulleyJointDef;
import org.jbox2d.dynamics.joints.RevoluteJoint;
import org.jbox2d.dynamics.joints.RevoluteJointDef;

import android.graphics.Canvas;
import android.graphics.Paint;


/**
* @author oven:
* @version 创建时间：2009-1-1 上午5:58:25
* 
*/
public class JBox2dUtil {
	public final static int RATE = 30;//屏幕到现实世界的比例 30px：1m;
	public final static int DEF_DENSITY=1;//默认密度
	public final static float DEF_FRICTION=0.5f;//默认摩擦力
	public final static float DEF_RESTITUTION=0.5f;//默认弹性系数[0.0~1.0,系数越大弹性越大]
	
	/**
	 * 创建一个矩形
	 * @param x 左上角
	 * @param y
	 * @param width
	 * @param height
	 * @param world
	 * @param density
	 * @param friction
	 * @param restitution
	 */
	public static Body createBox(float x,float y,float width,float height,World world,int density,float friction ,float restitution,boolean isStatic){
		//定义一个多边形
		PolygonShape shape = new PolygonShape();
		//设置多边形的大小
		shape.setAsBox(width/2/RATE, height/2/RATE);
		x=x+width/2;
		y=y+height/2;
    	return createShapeBody(x,y,shape,world,density,friction,restitution,isStatic);
	}
	
	public static Body createBox(float x,float y,float width,float height,World world,boolean isStatic){
		return createBox(x,y,width,height,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,isStatic);
	}
	
	public static Body createStaticBox(float x,float y,float width,float height,World world){
		return createBox(x,y,width,height,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,true);
	}
	
	public static Body createDynamicBox(float x,float y,float width,float height,World world){
		return createBox(x,y,width,height,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,false);
	}
	
	/**
	 * 创建一个圆形
	 * @param x 圆心位置  
	 * @param y
	 * @param radius
	 * @param world
	 * @param density
	 * @param friction
	 * @param restitution
	 * @param isStatic
	 * @return
	 */
	public static Body createCircle(float x,float y,float radius,World world,int density,float friction ,float restitution,boolean isStatic){
		CircleShape shape = new CircleShape();
		shape.m_radius=radius/RATE;
		return createShapeBody(x,y,shape,world,density,friction,restitution,isStatic);
    }
	
	public static Body createCircle(float x,float y,float radius,World world,boolean isStatic){
		return createCircle(x,y,radius,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,isStatic);
	}
	
	public static Body createStaticCircle(float x,float y,float radius,World world){
		return createCircle(x,y,radius,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,true);
	}
	
	public static Body createDynamicCircle(float x,float y,float radius,World world){
		return createCircle(x,y,radius,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,false);
	}
	
	
	/**
	 * 创建一个多边形
	 * @param vertices 顶点
	 * (数值是以屏幕坐标为尺度,相对物体中心点的偏移量)
	 * @param x 左上角
	 * @param y
	 * @param world
	 * @param density
	 * @param friction
	 * @param restitution
	 */
	public static Body createShape(float[] vertexs,float x,float y,World world,int density,float friction ,float restitution,boolean isStatic){
		//定义一个多边形
		PolygonShape shape = new PolygonShape();
		//定义顶点
		int vec2Count = vertexs.length/2;
		Vec2[] vec2s = new Vec2[vec2Count];
		for(int i =0 ;i<vec2Count;i++){
			//转化为物理世界中相对物体的偏移量
			vec2s[i]=new Vec2(vertexs[i*2]/RATE,vertexs[i*2+1]/RATE);
		}
		shape.set(vec2s, vec2Count);
		//根据顶点,获取物体的宽高
		float[] values = getWidthHeight(vec2s);
		//计算物体的中心点
		x=x+values[0]/2;
		y=y+values[1]/2;
    	return createShapeBody(x,y,shape,world,density,friction,restitution,isStatic);
	}
	
	public static Body createShape(float[]vertexs,float x,float y,World world,boolean isStatic){
		return createShape(vertexs,x,y,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,isStatic);
	}
	
	public static Body createStaticShape(float[]vertexs,float x,float y,World world){
		return createShape(vertexs,x,y,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,true);
	}
	
	public static Body createDynamicShape(float[]vertexs,float x,float y,World world){
		return createShape(vertexs,x,y,world,DEF_DENSITY,DEF_FRICTION,DEF_RESTITUTION,false);
	}
	
	/**
	 * 创建一个物体
	 * @param x 中心点x
	 * @param y 中心点y
	 * @param shape
	 * @param world
	 * @param density
	 * @param friction
	 * @param restitution
	 * @param isStatic
	 * @return
	 */
	public static Body createShapeBody(float x,float y,Shape shape,World world,int density,float friction ,float restitution,boolean isStatic){
		//具有物理属性的多边形
			FixtureDef fd = new FixtureDef(); 
			fd.shape = shape;
			if(isStatic){
				/**密度不为0时，在物理世界中会受外力影响 */  
				fd.density=0;//密度
			}else{
				fd.density=density;
			}
			fd.friction=friction;//摩擦力
			fd.restitution=restitution;//弹性系数
			
			//--------------------------世界中的物体的容器
			//定义一个世界中的物体,就是地面的对象
	    	BodyDef bodyDef = new BodyDef();
	    	//物体是定义静态或动态
	    	bodyDef.type=isStatic?BodyType.STATIC : BodyType.DYNAMIC;
	    	//定义这个物体在世界中的位置
	    	bodyDef.position.set(x/RATE, y/RATE);
	    	//把这个物体放置在世界中,返回存放在这个世界中的一个可操作的对象
	    	Body body= world.createBody(bodyDef);
	    	
	    	//把属性绑定到这个物体上(相当于皮肤)
	    	body.createFixture(fd);

	    	return body;
	}
	
	
	/**
	 * 绘制形状
	 * @param body
	 * @param canvas
	 */
	public static void drawShape(Body body,Canvas canvas){
		canvas.save();
		Paint paint = Tools.createNewPaint();
		Vec2 position = body.getPosition();
		if(body.getFixtureList().m_shape.m_type!=ShapeType.POLYGON)
			return;
		PolygonShape shape = (PolygonShape)(body.getFixtureList().m_shape);
		Vec2[] vertexs=shape.m_vertices;
		int vertexCount = shape.m_vertexCount;
		canvas.rotate((float) (body.getAngle() * 180 / Math.PI),position.x * RATE, position.y * RATE);
		for(int i=0;i<vertexCount;i++){
			Vec2 vertexs1;
			Vec2 vertexs2;
			if(i==vertexCount-1){
				vertexs1= vertexs[i];
				vertexs2= vertexs[0];
			}else{
				vertexs1= vertexs[i];
				vertexs2= vertexs[i+1];
			}
			float point1x=RATE*(position.x+vertexs1.x);
			float point1y=RATE*(position.y+vertexs1.y);
			float point2x=RATE*(position.x+vertexs2.x);
			float point2y=RATE*(position.y+vertexs2.y);
			canvas.drawLine(point1x, point1y, point2x, point2y,paint);
		}
		canvas.restore();
	}
	
	
	public static void drawJoint(Joint j,Canvas canvas,Paint paint){
		switch(j.m_type){
		case MOUSE:
			drawMouseJoint((MouseJoint)j, canvas, paint);
			break;
		case DISTANCE:
			drawDistanceJoint((DistanceJoint)j, canvas, paint);
			break;
		case PRISMATIC:
			break;
		case REVOLUTE:
			break;
		case WELD:
			break;
		case FRICTION:
			break;
		case LINE:
			break;
		case GEAR:
			break;
		case PULLEY:
			drawPulleyJoint((PulleyJoint)j, canvas, paint);
			break;
		case CONSTANT_VOLUME:
		}
	}
	/**
	 * 绘制距离关节
	 * @param body
	 * @param canvas
	 */
	public static void drawDistanceJoint(DistanceJoint dj,Canvas canvas,Paint paint){
		canvas.drawLine(dj.getBodyA().getWorldCenter().x* RATE,dj.getBodyA().getWorldCenter().y* RATE,
					    dj.getBodyB().getWorldCenter().x* RATE,dj.getBodyB().getWorldCenter().y* RATE,
					    paint);
		
	}
	
	/**
	 * 绘制距离关节
	 * @param body
	 * @param canvas
	 */
	public static void drawDistanceJoint(DistanceJoint dj,Canvas canvas){
		drawDistanceJoint(dj,canvas,Tools.createNewPaint());
	}
	
	
	/**
	 * 绘制滑轮关节
	 */
	public static void drawPulleyJoint(PulleyJoint pj,Canvas canvas,Paint paint){
		Vec2 ga1=pj.getGroundAnchorA();
		Vec2 ga2=pj.getGroundAnchorB();
		Vec2 bodyVc1=pj.getBodyA().getWorldCenter();
		Vec2 bodyVc2=pj.getBodyB().getWorldCenter();
		drawVec2Line(ga1,ga2,canvas,paint);
		drawVec2Line(ga1,bodyVc1,canvas,paint);
		drawVec2Line(ga2,bodyVc2,canvas,paint);
	}
	
	/**
	 * 绘制滑轮关节
	 */
	public static void drawPulleyJoint(PulleyJoint pj,Canvas canvas){
		drawPulleyJoint(pj,canvas,Tools.createNewPaint());
	}
	
	
	/**
	 * 绘制鼠标关节
	 * @param mj
	 * @param canvas
	 * @param paint
	 */
	public static void drawMouseJoint(MouseJoint mj,Canvas canvas,Paint paint){
		Vec2 v1=mj.getTarget();
		Vec2 v2 = mj.getBodyB().getWorldCenter();
		drawVec2Line(v1, v2, canvas, paint);
	}
	
	public static void drawMouseJoint(MouseJoint mj,Canvas canvas){
		drawMouseJoint(mj,canvas,Tools.createNewPaint());
	}
	
	/**
	 * 绘制两个vec2之间的线段
	 */
	public static void drawVec2Line(Vec2 v1,Vec2 v2,Canvas canvas,Paint paint){
		canvas.drawLine(v1.x* RATE,v1.y* RATE,v2.x* RATE,v2.y* RATE,paint);
	}
	
	public static float[] getWidthHeight(Vec2[] vertexs){
		float[] result = new float[2];
		float minx=0;
		float miny=0;
		float maxx=0;
		float maxy=0;
		for(int i=0;i<vertexs.length;i++){
			Vec2 v = vertexs[i];
			if(v.x<=minx){
				minx=v.x;
			}
			if(v.x>=maxx){
				maxx=v.x;
			}
			if(v.y<=miny){
				miny=v.y;
			}
			if(v.y>=maxy){
				maxy=v.y;
			}
		}
		result[0] = (maxx-minx)*JBox2dUtil.RATE;
		result[1] = (maxy-miny)*JBox2dUtil.RATE;
		return result;
	}
	
	
	/**
	 * 创建一个距离关节
	 * @param body1
	 * @param body2
	 * @param world
	 * @return
	 */
	public static DistanceJoint createDistanceJoint(Body body1,Body body2,World world) {
		if(world==null){
			world =body1.m_world;
		}
		//创建一个距离关节数据实例
		DistanceJointDef dje = new DistanceJointDef();
		// 初始化关节数据
		dje.initialize(body1, body2, body1.getWorldCenter(), body2.getWorldCenter());
		// dje.collideConnected=true;
		//利用世界通过传入的距离关节数据创建一个关节
		DistanceJoint dj = (DistanceJoint) world.createJoint(dje);
		return dj;
	}
	
	/**
	 * 创建一个距离关节
	 * @param body1
	 * @param body2
	 * @return
	 */
	public static DistanceJoint createDistanceJoint(Body body1,Body body2) {
		return createDistanceJoint(body1,body2,null);
	}
	
	
	/**
	 * 创建一个旋转关节
	 * @param body1 旋转的
	 * @param body2 静态的
	 * @param world
	 * @param maxMotorTorque 马达的预期最大扭矩(即开始的旋转速度)
	 * @param motorSpeed 马达最终扭矩(即稳定后的速度)
	 * @param enableMotor 是否启动马达
	 * @param revPoint 旋转中心
	 * @return
	 */
	public static RevoluteJoint createRevoluteJoint(Body body1,Body body2,World world,float maxMotorTorque,float motorSpeed,boolean enableMotor,Vec2 revPoint) {
		if(world==null){
			world =body1.m_world;
		}
		//创建一个旋转关节的数据实例 
		RevoluteJointDef rjd = new RevoluteJointDef();
		if(revPoint==null){
			revPoint=body1.getWorldCenter();
		}
		//初始化旋转关节数据
		rjd.initialize(body1, body2, revPoint);
		if(!(maxMotorTorque==0&&motorSpeed==0)){
			/**
			 * 如果预期扭矩比最终扭矩小,则需要考虑预期扭矩力是否能克服重力使旋转body旋转
			 */
			rjd.maxMotorTorque = maxMotorTorque;// 马达的预期最大扭矩(即开始的旋转速度)
			rjd.motorSpeed =motorSpeed;//马达最终扭矩(即稳定后的速度)
			rjd.enableMotor = enableMotor;// 启动马达
		}
		//利用world创建一个旋转关节
		RevoluteJoint rj = (RevoluteJoint)world.createJoint(rjd);
		return rj ;
	}
	
	/**
	 * 创建一个旋转关节
	 * @param body1 旋转的
	 * @param body2 静态的
	 * @param world
	 * @param maxMotorTorque 马达的预期最大扭矩(即开始的旋转速度)
	 * @param motorSpeed 马达最终扭矩(即稳定后的速度)
	 * @param enableMotor 是否启动马达
	 * @return
	 */
	public static RevoluteJoint createRevoluteJointCenter(Body body1,Body body2,World world,float maxMotorTorque,float motorSpeed,boolean enableMotor) {
		return createRevoluteJoint(body1,body2,world,maxMotorTorque,motorSpeed,enableMotor,null);
	}
	
	/**
	 * 创建一个旋转关节
	 * @param body1 旋转的
	 * @param body2 静态的
	 * @param maxMotorTorque 马达的预期最大扭矩(即开始的旋转速度)
	 * @param motorSpeed 马达最终扭矩(即稳定后的速度)
	 * @param enableMotor 是否启动马达
	 * @return
	 */
	public static RevoluteJoint createRevoluteJointCenter(Body body1,Body body2,float maxMotorTorque,float motorSpeed) {
		return createRevoluteJoint(body1,body2,null,maxMotorTorque,motorSpeed,true,null);
	}
	
	
	/**
	 * 创建一个旋转关节
	 * @param body1 旋转的
	 * @param body2 静态的
	 * @return
	 */
	public static RevoluteJoint createRevoluteJointCenter(Body body1,Body body2) {
		return createRevoluteJoint(body1,body2,null,0,0,false,null);
	}
	
	
	/**
	 * 创建齿轮关节
	 * @return
	 */
	public static GearJoint createGearJoint(RevoluteJoint rj1,RevoluteJoint rj2,World world) {
		if(world==null){
			world =rj1.m_bodyA.m_world;
		}
		//创建齿轮关节数据实例
		GearJointDef gjd = new GearJointDef();
		//设置齿轮关节的两个Body
		gjd.bodyA = rj1.m_bodyA;
		gjd.bodyB = rj2.m_bodyA;
		//设置齿轮关节绑定的两个旋转关节
		gjd.joint1 = rj1;
		gjd.joint2 = rj2;
		//设置旋转角度比
		gjd.ratio = 1;
		//通过world创建一个齿轮关节
		GearJoint gj = (GearJoint) world.createJoint(gjd);
		return gj;
	}
	
	/**
	 * 创建齿轮关节
	 * @return
	 */
	public static GearJoint createGearJoint(RevoluteJoint rj1,RevoluteJoint rj2) {
		return createGearJoint(rj1,rj2,null);
	}
	
	
	/**
	 * 创建滑轮关节
	 * @param body1
	 * @param body2
	 * @param anchor1x
	 * @param anchor1y
	 * @param anchor2x
	 * @param anchor2y
	 * @param r 拉伸长度比例
	 * @param world
	 * @return
	 */
	public static PulleyJoint createPulleyJoint(Body body1,Body body2 ,float anchor1x,float anchor1y,float anchor2x,float anchor2y,float r,World world) {
		//创建滑轮关节数据实例
		PulleyJointDef pjd = new PulleyJointDef();
		if(world==null){
			world=body1.m_world;
		}
		Vec2 ga1 = new Vec2(anchor1x/ RATE,anchor1y/ RATE);
		Vec2 ga2 = new Vec2(anchor2x/ RATE,anchor2y/ RATE); 
		//初始化滑轮关节数据
		//body，两个滑轮的锚点，两个body的锚点，比例系数
		pjd.initialize(body1, body2, ga1, ga2, body1.getWorldCenter(), body2.getWorldCenter(), r);
		PulleyJoint pj = (PulleyJoint) world.createJoint(pjd);
		return pj;
	}
	
	
	/**
	 * 创建滑轮关节
	 * @param body1
	 * @param body2
	 * @param anchor1x
	 * @param anchor1y
	 * @param anchor2x
	 * @param anchor2y
	 * @param r 拉伸长度比例
	 * @return
	 */
	public static PulleyJoint createPulleyJoint(Body body1,Body body2 ,float anchor1x,float anchor1y,float anchor2x,float anchor2y,float r) {
		return createPulleyJoint(body1, body2, anchor1x, anchor1y, anchor2x, anchor2y, r,null);
	}
	
	
	// 鼠标关节
	public static MouseJoint createMouseJoint(Body body,World world) {
		MouseJointDef mjd = new MouseJointDef();
		//设置鼠标关节的第一个Body实例（默认使用接地Body）
		if(world == null){
			world = body.getWorld();
		}
		mjd.bodyA = world.getBodyList();
		//设置鼠标关节的第二个Body实例(被拖拽的Body)
		mjd.bodyB = body;
		//设置目标点的X坐标
		mjd.target.x = body.getPosition().x;
		//设置目标点的Y坐标
		mjd.target.y = body.getPosition().y;
		// body1.allowSleeping(false);//设置body1永不休眠
		// 设置鼠标关节的目标位置
		mjd.maxForce = 100;// 拉力
		//由World来创建鼠标关节
		MouseJoint mj = (MouseJoint) world.createJoint(mjd);
		return mj;
	}
	
	public static MouseJoint createMouseJoint(Body body) {
		return createMouseJoint(body,null);
	}
	
}

